package com.jin.webvideo.util;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Map;


public class SimpleTemplateParser {
    private class SimpleTemplateContext extends TemplateParserContext {
        protected SimpleTemplateContext() {
            super("{", "}");
        }
    }
    private TemplateParserContext simpleTemplateContext = new SimpleTemplateContext();
    private ExpressionParser expressionParser;
    private StandardEvaluationContext context;

    private Cache<String, Expression> cache;

    public SimpleTemplateParser(ExpressionParser expressionParser, StandardEvaluationContext context, CacheBuilder<Object, Object> builder) {
        this.expressionParser = expressionParser;
        this.context = context;
        this.cache = builder.build();
    }

    public SimpleTemplateParser(CacheBuilder<Object, Object> builder) {
        this(new SpelExpressionParser(), new StandardEvaluationContext(), builder);
    }

    public void setContext(StandardEvaluationContext context) {
        this.context = context;
    }

    public void setExpressionParser(ExpressionParser expressionParser) {
        this.expressionParser = expressionParser;
    }

    public <T> T  getValue(String expressionStr, Class<? extends T> clazz) {
        Expression expression = parseExpression(expressionStr);

        return expression.getValue(context, clazz);
    }

    public void setVariable(String name, Object value) {
        context.setVariable(name, value);
    }

    public void setVariables(Map<String, Object> variables) {
        if (variables == null) {
            return;
        }
        context.setVariables(variables);
    }

    public void registerFunction(String name, Method method) {
        context.registerFunction(name, method);
    }

    /**
     * 只注册 public static方法
     * @param clazz
     */
    public void registerFunction(Class<?> clazz) {
        for (Method method : ReflectionUtils.getDeclaredMethods(clazz)) {
            int modifier = method.getModifiers();
            if (Modifier.isStatic(modifier) && Modifier.isPublic(modifier)) {
                registerFunction(method.getName(), method);
            }
        }
    }

    private Expression parseExpression(String expressionStr) {
        Expression expression = cache.getIfPresent(expressionStr);
        if (expression != null) {
            return expression;
        }
        expression = expressionParser.parseExpression(expressionStr, simpleTemplateContext);
        cache.put(expressionStr, expression);
        return expression;
    }
}
